package com.bobi.tfca.netty;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bobi.tfca.model.entity.GroupMemberEntity;
import com.bobi.tfca.model.entity.GroupMessageEntity;
import com.bobi.tfca.model.entity.MessageEntity;
import com.bobi.tfca.model.enums.MessageCategoryEnum;
import com.bobi.tfca.model.enums.MessageContentTypeEnum;
import com.bobi.tfca.model.enums.MessageStatusEnum;
import com.bobi.tfca.model.vo.MessageVO;
import com.bobi.tfca.service.GroupMemberService;
import com.bobi.tfca.service.GroupMessageService;
import com.bobi.tfca.service.GroupService;
import com.bobi.tfca.service.MessageService;
import com.bobi.tfca.utils.DateTimeUtil;
import com.google.gson.Gson;

import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;

@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {

    @Autowired
    private MessageService messageService;

    @Autowired
    private GroupMessageService groupMessageService;

    @Autowired
    private GroupMemberService groupMemberService;

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        // Channel失效，从Map中移除
        NettyChannelMap.remove(ctx.channel());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
        log.info(msg);
        Gson gson = new Gson();
        MessageVO message = gson.fromJson(msg, MessageVO.class);
        // 设置一下发送时间
        String sendTime = DateTimeUtil.localDateTimeConvertString(LocalDateTime.now());
        message.setSendTime(sendTime);
        message.setMessageStatus(MessageStatusEnum.RECEIVED.getCode());

        if (Objects.equals(message.getContentType(), MessageContentTypeEnum.PING.getCode())) {
            System.out.println("received ping from " + message.getSenderId());
            Channel channel = NettyChannelMap.get(message.getSenderId());
            if (channel != null) {
                channel.writeAndFlush(message.toJson());
            }
        } else if (Objects.equals(message.getContentType(), MessageContentTypeEnum.LOGIN.getCode())) {
            log.info(message.toString());
            NettyChannelMap.add(message.getSenderId(), ctx.channel());
        }  else if (Objects.equals(message.getContentType(), MessageContentTypeEnum.TEXT.getCode())) {
            // 存储消息
            MessageEntity entity = MessageEntity.ofMessageVO(message);
            entity.setCategory(MessageCategoryEnum.GROUP_CHAT.getCode());
            entity.setMessageId(null);
            messageService.save(entity);
            GroupMessageEntity groupMessageEntity = new GroupMessageEntity();
            groupMessageEntity.setMessageId(entity.getMessageId());
            groupMessageEntity.setGroupId(message.getGroupId());
            // 设置未读
            // 查询全部群成员
            List<GroupMemberEntity> memberEntityList = groupMemberService.list(new LambdaQueryWrapper<GroupMemberEntity>().eq(GroupMemberEntity::getGroupId, message.getGroupId())
                    .select(GroupMemberEntity::getMemberId));
            StringJoiner joiner = new StringJoiner(",");

            for (GroupMemberEntity item : memberEntityList) {
                // 自己发的，这条消息不可能未读，在线的也不可能未读
                if (!Objects.equals(item.getMemberId(), message.getSenderId())) {
                    joiner.add("{" + item.getMemberId() + "}"); // 在每个元素周围加上花括号{}
                }
            }
            String result = joiner.toString();
            groupMessageEntity.setUnreadMembers(result);
            groupMessageService.save(groupMessageEntity);
            log.info(groupMessageEntity.toString());

            // 设置消息Id
            message.setMessageId(entity.getMessageId());

            // 群聊应该发送给所有人，除了自己
            Map<Integer, Channel> channels = NettyChannelMap.getMap();
            for (Map.Entry<Integer, Channel> entry : channels.entrySet()) {
                log.info("Socket Alive Member --->>>" + entry.getKey());
                Integer memberId = entry.getKey();
                Channel channel = entry.getValue();
                if (!Objects.equals(memberId, message.getSenderId())) {
                    if (channel != null) {
                        channel.isWritable();
                        channel.writeAndFlush(message.toJson()).addListener((ChannelFutureListener) future -> {
                            if (!future.isSuccess()) {
                                log.error("send msg to " + memberId + " failed");
                            }
                        });
                    }
                }
            }
        }
        ReferenceCountUtil.release(msg);
    }
}